import os
import tempfile
from pathlib import Path
from typing import Optional, Any

import yaml
import logger_config


class ConfigManager:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._load_config()
            cls.logger = logger_config.setup_logger("config_manager")
        return cls._instance


    def _load_config(self) -> dict:
        """
        Load configuration from YAML file.
        """
        config_file = Path(__file__).parent / "config.yaml"
        config_path = Path(config_file)
        if not config_path.exists():
            raise FileNotFoundError(f"Config file '{config_file}' not found.")

        try:
            with open(config_file, "r") as file:
                self._config = yaml.safe_load(file) or {}
            return self._config or {}
        except Exception as e:
            self.logger.error(f"Failed to load configuration: {e}")
            raise  # Re-raise the exception after logging

    def save_config(self, config: dict) -> None:
        """
        Save configuration to YAML file with atomic write and error handling.
        """
        config_file = Path(__file__).parent / "config.yaml"
        if not isinstance(config, dict):
            raise ValueError("Config must be a dictionary.")

        try:
            # Create a temporary file in the same directory for atomic write
            temp_fd, temp_path = tempfile.mkstemp(dir=config_file.parent, suffix=".tmp")
            with os.fdopen(temp_fd, "w") as tmpfile:
                yaml.safe_dump(config, tmpfile)

            # Atomically replace the old file
            os.replace(temp_path, config_file)
            self.logger.info("Configuration saved successfully.")
        except Exception as e:
            self.logger.error(f"Failed to save configuration: {e}")
            raise  # Re-raise the exception after logging

    def get_config(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
        """
        获取配置值，支持 a.b.c 链式 key。
        返回对应的配置值，若路径不存在则返回 default。
        """
        if not isinstance(key, str):
            return default

        # 先尝试直接匹配
        if key in self._config:
            return self._config[key]

        # 处理链式 key
        keys = key.split(".")
        current = self._config
        for k in keys:
            if not isinstance(current, dict):
                return default
            if k in current:
                current = current[k]
            else:
                return default

        return current

    def set_config(self, key: str, value: Any) -> None:
        """
        设置配置值，支持 a.b.c 链式 key。
        """
        if not isinstance(key, str) or not key:
            return # 或者抛出 ValueError("key 不能为空字符串")

        keys = [k for k in key.split(".") if k]  # 过滤掉空字符串
        if not keys:
            return  # 或者抛出 ValueError("key 不能为空字符串")

        current = self._config
        if not isinstance(current, dict):
            raise TypeError("self.config 必须是字典类型")

        for k in keys[:-1]:
            if not isinstance(current, dict):
                raise TypeError("配置项必须是字典类型")
            if k not in current:
                current[k] = {}
            current = current[k]

        if not isinstance(current, dict):
            raise TypeError("配置项必须是字典类型")

        current[keys[-1]] = value
        self.save_config(self._config)


# 创建全局单例实例
config_manager = ConfigManager()

